
import requests
from bs4 import BeautifulSoup
from bs4.element import Tag
from config.header import headers

# 适用于选择器的处理函数，默认是什么都不做。


def default_handle(tag: Tag):
    return tag


class Spider:
    # 原始数据
    raw = None
    # 相应对象
    res = None
    # bs对象
    bs4 = None

    """ 构造函数 """

    def __init__(self, url):
        if(url == None):
            raise TypeError("URL 不能为空")

        self.res = requests.get(url=url, headers=headers)
        self.raw = self.res.content
        self.bs4 = BeautifulSoup(self.raw, "lxml")

    """ 选中多个 tag 并使用 handle 进行格式化(map) """

    def select(self, selector: str, handle=default_handle):
        return list(map(handle, self.bs4.select(selector)))

    """ 选中单个 tag 并使用 handle 进行格式化(map) """

    def select_once(self, selector: str, handle=default_handle):
        return handle(self.bs4.select_one(selector))

    # 保存
    def save(self):
        raise NotImplementedError()

    # 生成器
    @staticmethod
    def generator():
        raise NotImplementedError()

    # 装饰器
    class Decorators:
        # 装饰对象必须返回 tag 对象
        @staticmethod
        def text(func):
            def _func(*args, **kwargs):
                tags: list[Tag] = func(*args, **kwargs)
                if(isinstance(tags, list)):
                    return list(map(lambda tag: tag.text.strip(), tags))
                elif(isinstance(tags, Tag)):
                    return tags.text.strip()
                else:
                    raise TypeError()
            return _func
        # 装饰对象必须返回 tag 对象

        @staticmethod
        def src(func):
            return Spider.Decorators.attr("src")(func)

        @staticmethod
        def attr(arrtibute_name: str):
            def attr_func(func):
                def _func(*args, **kwargs):
                    tags: list[Tag] = func(*args, **kwargs)
                    if(isinstance(tags, list)):
                        return list(map(lambda tag: tag.get(arrtibute_name).strip(), tags))
                    elif(isinstance(tags, Tag)):
                        return tags.get(arrtibute_name).strip()
                    else:
                        raise TypeError()
                return _func
            return attr_func

        # 将返回值转换成字典

        @staticmethod
        def field(name: str):
            def field_func(func):
                def _func(*args, **kwargs):
                    return {name: func(*args, **kwargs)}
                return _func
            return field_func
        # 如果只选中一个 tag ，可以使用这个装饰器返回列表中的第一个元素

        @staticmethod
        def one(func):
            def _func(*args, **kwargs):
                # print(func(self,tag))
                return func(*args, **kwargs)[0]
            return _func
